//
//  UIBezierPath+ALExtension.swift
//  ALCore
//
//  Created by IdeaBank on 2023/12/18.
//

import Foundation
public extension UIBezierPath {

    /// 通过CGPoint数组绘制多边形路径
    static func NGon(points: [CGPoint]) -> UIBezierPath? {
        guard points.count > 2 else {return nil}
        let path = UIBezierPath()
        path.move(to: points[0])
        for point in points[1...] {
            path.AL_addLine(to: point)
        }
        path.close()
        return path
    }

    enum NGonOrigin {
        case top, bottom, left, right
    }

    /// 绘制正多边形路径
    ///
    /// - Parameters:
    ///   - center: 圆心点坐标 (正多形的外接圆)
    ///   - radius: 正多边形的半径
    ///   - sides: 边数 (至少为3)
    ///   - origin: 起始绘制点
    ///
    /// - Returns: 正多边形路径
    static func NGon(center: CGPoint, radius: CGFloat, sides: Int, origin: NGonOrigin)  -> UIBezierPath {
        func start() -> CGPoint {
            switch origin {
            case .top:
                return CGPoint(x: center.x, y: center.y - radius)
            case .bottom:
                return CGPoint(x: center.x, y: center.y + radius)
            case .left:
                return CGPoint(x: center.x - radius, y: center.y)
            case .right:
                return CGPoint(x: center.x + radius, y: center.y)
            }
        }

        func link(_ radian: CGFloat) -> CGPoint {
            switch origin {
            case .top:
                return CGPoint(x: center.x + radius * sin(radian), y: center.y - radius * cos(radian))
            case .bottom:
                return CGPoint(x: center.x + radius * sin(radian), y: center.y + radius * cos(radian))
            case .left:
                return CGPoint(x: center.x - radius * cos(radian), y: center.y + radius * sin(radian))
            case .right:
                return CGPoint(x: center.x + radius * cos(radian), y: center.y + radius * sin(radian))
            }
        }

        let count = max(3, sides)
        let path = UIBezierPath()
        path.move(to: start())
        for i in 0...count {
            let radian: CGFloat = .pi * CGFloat(2 * i) / CGFloat(count)
            path.AL_addLine(to: link(radian))
        }
        path.close()
        return path
    }

    /// 添加矩形框
    func addRect(_ rect: CGRect) {
        move(to: rect.origin)
        AL_addLine(to: CGPoint(x: rect.maxX, y: rect.minY))
        AL_addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
        AL_addLine(to: CGPoint(x: rect.minX, y: rect.maxY))
        close()
    }
}

public extension UIBezierPath {

    /// 将数组中的点连成普通折线
    static func normalPath(points: [CGPoint]) -> UIBezierPath {
        guard points.count > 0 else {
            return UIBezierPath()
        }

        let path = UIBezierPath()
        for index in 0 ..< points.count {
            let point = points[index]
            if index == 0 {
                path.move(to: point)
            } else {
                path.AL_addLine(to: point)
            }
        }
        return path
    }

    /// 将数组中的点连成平滑的曲线(granularity值越大越平滑)
    static func smoothPath(points: [CGPoint], granularity: Int = 3) -> UIBezierPath {
        guard points.count > 0 else {
            return UIBezierPath()
        }

        let smoothPath = UIBezierPath()
        var innerPoints = points
        innerPoints.insert(innerPoints[0], at: 0)
        innerPoints.append(innerPoints.last!)
        smoothPath.move(to: innerPoints[0])
        for index in 1 ..< innerPoints.count - 2 {
            let p0 = innerPoints[index - 1]
            let p1 = innerPoints[index]
            let p2 = innerPoints[index + 1]
            let p3 = innerPoints[index + 2]

            for i in 1 ..< granularity {
                let t = CGFloat(i) * (1.0 / CGFloat(granularity))
                let tt = t * t
                let ttt = tt * t

                var pi = CGPoint.zero
                pi.x = 0.5 * (2*p1.x+(p2.x-p0.x)*t + (2*p0.x-5*p1.x+4*p2.x-p3.x)*tt + (3*p1.x-p0.x-3*p2.x+p3.x)*ttt)
                pi.y = 0.5 * (2*p1.y+(p2.y-p0.y)*t + (2*p0.y-5*p1.y+4*p2.y-p3.y)*tt + (3*p1.y-p0.y-3*p2.y+p3.y)*ttt)
                smoothPath.AL_addLine(to: pi)
            }
            smoothPath.AL_addLine(to: p2)
        }
        return smoothPath
    }
}

fileprivate extension UIBezierPath {

    func AL_addLine(to point: CGPoint) {
        addLine(to: point)
    }
}
